package com.kyrie.security.shiro;

import com.kyrie.security.jwt.JWTFilter;
import com.kyrie.system.mybatis.service.IDefaultService;
import com.kyrie.utils.GlobalConstants;
import com.kyrie.vo.TOperationCommTypeVal;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/***
 * 描述: Shiro配置类
 *
 * @author wuxiang
 * @date 2020-04-07 10:38
 */
@Configuration
public class ShiroConfig {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${shiro.anonMappings}")
    private String anonMappings;

    /**
     * 注入ShiroFilterFactoryBean
     * @param securityManager SecurityManager
     * @return ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean factory (SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加jwt过滤器
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        // 添加自定义的JWT过滤器
        filterMap.put("jwt", new JWTFilter());

        factoryBean.setFilters(filterMap);
        factoryBean.setSecurityManager(securityManager);

        // 设置无权限时跳转的URL
        factoryBean.setUnauthorizedUrl("/500?errorMsg=" + GlobalConstants.LIMITED_REQUEST);

        // 设置请求URL规则配置
        Map<String, String> fileterRuleMap = new HashMap<>();
        // 设置所有的请求都要通过自定义的jwt过滤器
        fileterRuleMap.put("/**","jwt");

        logger.info("无认证mappings：{}",anonMappings);
        if (StringUtils.isNotEmpty(anonMappings)) {
            String[] mappingArr = anonMappings.split(";");
            for (int i = 0; i < mappingArr.length; i++) {
                /*fileterRuleMap.put(mappingArr[i],"anon");*/
                fileterRuleMap.put(mappingArr[i],GlobalConstants.ANON_VAL_CODE);
            }
        }

        // 将规则添加到ShiroFilterFactoryBean中
        factoryBean.setFilterChainDefinitionMap(fileterRuleMap);

        return factoryBean;
    }

    /**
     * 注入securityManager
     * @param shiroRealm 自定义的ShiroRealm
     */
    @Bean
    public SecurityManager securityManager (ShiroRealm shiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 设置自定义的Realm
        securityManager.setRealm(shiroRealm);

        // 关闭shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * 添加注解支持
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        // 强制使用cglib，防止重复代理和可能引起代理出错的问题
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * 此处将shiro生命周期设置为静态，才能使用配置文件属性
     */
    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}
